home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C++ / Snippets / QD3D Juggler / Juggler Sources / ObjectHandle.h < prev    next >
Encoding:
Text File  |  1995-12-27  |  6.4 KB  |  201 lines  |  [TEXT/CWIE]

  1. //
  2. //    ObjectHandle.h
  3. //
  4. //    Template Classes for creating dynamic objects inside of a Macintosh handle.
  5. //    There are no virtual methods so that the "envelope" classes are no bigger
  6. //    than an ordinary handle.
  7. //
  8. //    The contained classes must have a default constructor.
  9. //
  10. //    class ObjectHandle<Type>        Holds a single object.
  11. //    class ObjectArrayHandle<Type>    Holds an array of objects.
  12. //
  13. //    Note: I'm using a non-standard method of construction and destruction.
  14. //    See "Advanced C++ Programming Styles and Idioms" by James Coplien, pg 80.
  15. //
  16. //    James Jennings
  17. //    Started October 13, 1995
  18. //
  19. //    Written for SC++ v8 and CodeWarrior v7.
  20. //    Note: The SC++ v7.0.4 compiler generates an error on:
  21. //        ((Type*)*theObject)->~Type();
  22. //    You need the v8.0 compiler update. (Available on AOL.)
  23. //
  24.  
  25. #pragma once
  26.  
  27. #include <new.h>    // to get the overloaded version of operator new()
  28.  
  29. class AbstractObjectHandle {
  30. // Has the methods that don't require a template.
  31. // Declared here to limit the method explosion that templates give
  32.     enum { kIsLocked = 0x80 };
  33. protected:
  34.     // a protected constructor keeps it an abstract class
  35.     AbstractObjectHandle(void) : theObject(0) {}
  36.     ~AbstractObjectHandle(void) { DisposeHandle(theObject); theObject = 0; }
  37.     Handle theObject;    // where the data is stored
  38. public:
  39.     // Handle maintenence
  40.     Boolean IsValid(void)    { return theObject!=0 && *theObject!=0 ; }
  41.     void Lock(void)   { HLock(theObject); }
  42.     void Unlock(void) { HUnlock(theObject); }
  43.     Boolean IsLocked(void)    { return (HGetState(theObject) & kIsLocked) != 0; }
  44.     Boolean Lock(Boolean lock)
  45.         { Boolean old = IsLocked(); lock ? Lock() : Unlock(); return old; }
  46.     void MoveHi(void)        { MoveHHi(theObject); }
  47. private:
  48.     // Since nothing is virtual, we don't want people to 
  49.     // subclass this and then make a pointer to it.
  50.     // Declaring a private operator new will stop them.
  51.     void * operator new(size_t);
  52. #if _HAS_ARRAY_NEW    // I'd like to forbid new arrays too, but this doesn't compile.
  53.     void * operator new[](size_t);
  54. #endif
  55. };
  56.  
  57. //////////////////////////////////////////////////////////////////////
  58.  
  59. template <class Type>
  60. class ObjectHandle : public AbstractObjectHandle {
  61. // An object that looks like a pointer. It points to another object
  62. // which is stored in a Macintosh Handle.
  63. public:
  64.     ObjectHandle(Boolean longLived = false);    // constructor
  65.     ~ObjectHandle(void);// destructor
  66.     // make it look like a pointer to a Type
  67.     Type * operator->(void) { return *(Type**)(theObject); }    
  68. };
  69.  
  70. template<class Type>
  71. ObjectHandle<Type>::ObjectHandle(Boolean longLived) {
  72.     if (longLived) // make room at the bottom of the heap
  73.         ReserveMem(sizeof(Type));
  74.     // allocate the memory as a handle
  75.     theObject = NewHandle(sizeof(Type));
  76.     if (theObject) {    // if the handle is good...
  77.         Boolean oldLock = Lock(true);    // lock it...
  78.         Type *t = new (*theObject) Type;    // trigger the constructor...
  79.         Lock(oldLock);        // restore the lock
  80.     }
  81. }
  82.  
  83. template<class Type>
  84. ObjectHandle<Type>::~ObjectHandle(void) {
  85.     if (theObject) {    // if the handle is good...
  86.         Boolean oldLock = Lock(true);    // lock it...
  87.         // We can't use "delete" because the memory wasn't malloc'ed
  88.         (*(Type**)theObject)->Type::~Type(); // trigger the destructor...
  89.         Lock(oldLock);        // restore the lock
  90.     }
  91. }
  92.  
  93. //////////////////////////////////////////////////////////////////////
  94. /*    // We may want to create an intermediate array kind
  95.     // for holding built-in types. Eg:
  96. template<class Type>
  97. class ArrayHandle : public AbstractObjectHandle {
  98. public:
  99.     ArrayHandle(long cnt=1) { theObject = NewHandle(sizeof(Type)*cnt); }
  100.     // no destructor
  101.     Type & operator[](int i) { return *( ((Type*)*theObject) + i ); }
  102.     long GetSize(void);
  103.     Boolean SetSize(long size);
  104. };
  105.     // that would allow operator->() in the ObjectArrayHandle
  106. */
  107. //////////////////////////////////////////////////////////////////////
  108.  
  109. template<class Type>
  110. class ObjectArrayHandle : public AbstractObjectHandle {
  111. // An object that looks like an array. The actual array is
  112. // stored in a Macintosh handle.
  113. public:
  114.     ObjectArrayHandle(long cnt=1);    // constructor
  115.     ~ObjectArrayHandle(void);        // destructor
  116.     // make it look like a pointer to the 1st elt of the array
  117.     // NOTE: operator-> won't work for arrays of built-in types 
  118. //    Type * operator->(void) { return *(Type**)(theObject); }
  119.     // make it look like an array
  120.     Type & operator[](int i) { return *( (*(Type**)theObject) + i ); }
  121.     long GetSize(void);
  122.     Boolean SetSize(long size);
  123. protected:
  124.     // allocation utilities
  125.     void ConstructRange(long start, long end);
  126.     void DestructRange(long start, long end);
  127. };
  128.  
  129. template<class Type>
  130. void ObjectArrayHandle<Type>::ConstructRange(long start, long end)
  131. {    // apply the constuctor to a range of objects
  132.     if (IsValid()) {
  133.         Boolean oldLock = Lock(true);    // lock it...
  134.         for (long i=start; i<=end; i++)
  135.             Type *t = new ( (*(Type**)theObject) + i ) Type;    // trigger each constructor
  136.         Lock(oldLock);    // restore the lock
  137.     }
  138. }
  139.  
  140. template<class Type>
  141. void ObjectArrayHandle<Type>::DestructRange(long start, long end)
  142. {    // apply the destructor to a range of objects
  143.     if (IsValid()) {
  144.         Boolean oldLock = Lock(true);    // lock it...
  145.         for (long i=end; i>=start; i--) {
  146.             // destruct each object (in reverse order)
  147.             Type *t = (*(Type**)theObject) + i;
  148.             t->Type::~Type();    // trigger each destructor
  149.         }
  150.         Lock(oldLock);    // restore the lock
  151.     }
  152. }
  153.  
  154. template<class Type>
  155. ObjectArrayHandle<Type>::ObjectArrayHandle(long cnt) {
  156.     // allocate the memory as a handle
  157.     theObject = NewHandle( sizeof(Type) * cnt );
  158.     ConstructRange(0, cnt-1);
  159. }
  160.  
  161. template<class Type>
  162. ObjectArrayHandle<Type>::~ObjectArrayHandle(void) {
  163.     DestructRange(0, GetSize()-1);
  164. }
  165.  
  166. template<class Type>
  167. //inline
  168. long ObjectArrayHandle<Type>::GetSize(void)    
  169. {
  170.     return (IsValid() ? (GetHandleSize(theObject)/sizeof(Type)) : 0); 
  171. }
  172.  
  173. template<class Type>
  174. Boolean ObjectArrayHandle<Type>::SetSize(long size)
  175. {    // Change the number of objects in the array.
  176.     // Return true if successful.
  177.     // User note: more likely to work if Unlock()ed first.
  178.     if (!IsValid()) return false;
  179.     long oldSize = GetSize();
  180.     OSErr err = noErr;
  181.     if (oldSize<size) {
  182.         // array is getting bigger
  183.         SetHandleSize(theObject, sizeof(Type)*size);
  184.         err = MemError();
  185.         if (err==noErr)
  186.             ConstructRange(oldSize,size-1);
  187.     } else if (oldSize>size) {
  188.         // array is getting smaller
  189.         DestructRange(size,oldSize-1);
  190.         SetHandleSize(theObject, sizeof(Type)*size);
  191.         err = MemError();
  192.     } // else oldSize==size -- no change
  193.     return err==noErr;
  194. }
  195.  
  196. //////////////////////////////////////////////////////////////////////
  197.  
  198. // handy macros
  199. #define    OH    ObjectHandle
  200. #define OAH    ObjectArrayHandle
  201.